<template>
  <view class="uni-table-scroll" :class="{ 'table--border': border, 'border-none': !noData }">
    <!-- #ifdef H5 -->
    <table class="uni-table" border="0" cellpadding="0" cellspacing="0" :class="{ 'table--stripe': stripe }" :style="{ 'min-width': minWidth + 'px' }">
      <slot></slot>
      <tr v-if="noData" class="uni-table-loading">
        <td class="uni-table-text" :class="{ 'empty-border': border }">{{ emptyText }}</td>
      </tr>
      <view v-if="loading" class="uni-table-mask" :class="{ 'empty-border': border }"><div class="uni-table--loader"></div></view>
    </table>
    <!-- #endif -->
    <!-- #ifndef H5 -->
    <view class="uni-table" :style="{ 'min-width': minWidth + 'px' }" :class="{ 'table--stripe': stripe }">
      <slot></slot>
      <view v-if="noData" class="uni-table-loading">
        <view class="uni-table-text" :class="{ 'empty-border': border }">{{ emptyText }}</view>
      </view>
      <view v-if="loading" class="uni-table-mask" :class="{ 'empty-border': border }"><div class="uni-table--loader"></div></view>
    </view>
    <!-- #endif -->
  </view>
</template>

<script lang="ts">
/**
 * Table 表格
 * @description 用于展示多条结构类似的数据
 * @tutorial https://ext.dcloud.net.cn/plugin?id=3270
 * @property {Boolean} 	border 				是否带有纵向边框
 * @property {Boolean} 	stripe 				是否显示斑马线
 * @property {Boolean} 	type 					是否开启多选
 * @property {String} 	emptyText 			空数据时显示的文本内容
 * @property {Boolean} 	loading 			显示加载中
 * @event {Function} 	selection-change 	开启多选时，当选择项发生变化时会触发该事件
 */
export default {
  name: "uniTable",
  options: {
    virtualHost: true,
  },
  emits: ["selection-change"],
  props: {
    data: {
      type: Array,
      default() {
        return [];
      },
    },
    // 是否有竖线
    border: {
      type: Boolean,
      default: false,
    },
    // 是否显示斑马线
    stripe: {
      type: Boolean,
      default: false,
    },
    // 多选
    type: {
      type: String,
      default: "",
    },
    // 没有更多数据
    emptyText: {
      type: String,
      default: "没有更多数据",
    },
    loading: {
      type: Boolean,
      default: false,
    },
    rowKey: {
      type: String,
      default: "",
    },
  },
  data() {
    return {
      noData: true,
      minWidth: 0,
      multiTableHeads: [],
    };
  },
  watch: {
    loading(val) {},
    data(newVal) {
      let theadChildren = this.theadChildren;
      let rowspan = 1;
      if (this.theadChildren) {
        rowspan = this.theadChildren.rowspan;
      }

      // this.trChildren.length - rowspan
      this.noData = false;
      // this.noData = newVal.length === 0
    },
  },
  created() {
    // 定义tr的实例数组
    this.trChildren = [];
    this.thChildren = [];
    this.theadChildren = null;
    this.backData = [];
    this.backIndexData = [];
  },

  methods: {
    isNodata() {
      let theadChildren = this.theadChildren;
      let rowspan = 1;
      if (this.theadChildren) {
        rowspan = this.theadChildren.rowspan;
      }
      this.noData = this.trChildren.length - rowspan <= 0;
    },
    /**
     * 选中所有
     */
    selectionAll() {
      let startIndex = 1;
      let theadChildren = this.theadChildren;
      if (!this.theadChildren) {
        theadChildren = this.trChildren[0];
      } else {
        startIndex = theadChildren.rowspan - 1;
      }
      let isHaveData = this.data && this.data.length > 0;
      theadChildren.checked = true;
      theadChildren.indeterminate = false;
      this.trChildren.forEach((item, index) => {
        if (!item.disabled) {
          item.checked = true;
          if (isHaveData && item.keyValue) {
            const row = this.data.find((v) => v[this.rowKey] === item.keyValue);
            if (!this.backData.find((v) => v[this.rowKey] === row[this.rowKey])) {
              this.backData.push(row);
            }
          }
          if (index > startIndex - 1 && this.backIndexData.indexOf(index - startIndex) === -1) {
            this.backIndexData.push(index - startIndex);
          }
        }
      });
      // this.backData = JSON.parse(JSON.stringify(this.data))
      this.$emit("selection-change", {
        detail: {
          value: this.backData,
          index: this.backIndexData,
        },
      });
    },
    /**
     * 用于多选表格，切换某一行的选中状态，如果使用了第二个参数，则是设置这一行选中与否（selected 为 true 则选中）
     */
    toggleRowSelection(row, selected) {
      // if (!this.theadChildren) return
      row = [].concat(row);

      this.trChildren.forEach((item, index) => {
        // if (item.keyValue) {

        const select = row.findIndex((v) => {
          //
          if (typeof v === "number") {
            return v === index - 1;
          } else {
            return v[this.rowKey] === item.keyValue;
          }
        });
        let ischeck = item.checked;
        if (select !== -1) {
          if (typeof selected === "boolean") {
            item.checked = selected;
          } else {
            item.checked = !item.checked;
          }
          if (ischeck !== item.checked) {
            this.check(item.rowData || item, item.checked, item.rowData ? item.keyValue : null, true);
          }
        }
        // }
      });
      this.$emit("selection-change", {
        detail: {
          value: this.backData,
          index: this.backIndexData,
        },
      });
    },

    /**
     * 用于多选表格，清空用户的选择
     */
    clearSelection() {
      let theadChildren = this.theadChildren;
      if (!this.theadChildren) {
        theadChildren = this.trChildren[0];
      }
      // if (!this.theadChildren) return
      theadChildren.checked = false;
      theadChildren.indeterminate = false;
      this.trChildren.forEach((item) => {
        // if (item.keyValue) {
        item.checked = false;
        // }
      });
      this.backData = [];
      this.backIndexData = [];
      this.$emit("selection-change", {
        detail: {
          value: [],
          index: [],
        },
      });
    },
    /**
     * 用于多选表格，切换所有行的选中状态
     */
    toggleAllSelection() {
      let list = [];
      let startIndex = 1;
      let theadChildren = this.theadChildren;
      if (!this.theadChildren) {
        theadChildren = this.trChildren[0];
      } else {
        startIndex = theadChildren.rowspan - 1;
      }
      this.trChildren.forEach((item, index) => {
        if (!item.disabled) {
          if (index > startIndex - 1) {
            list.push(index - startIndex);
          }
        }
      });
      this.toggleRowSelection(list);
    },

    /**
     * 选中\取消选中
     * @param {Object} child
     * @param {Object} check
     * @param {Object} rowValue
     */
    check(child, check, keyValue, emit) {
      let theadChildren = this.theadChildren;
      if (!this.theadChildren) {
        theadChildren = this.trChildren[0];
      }

      let childDomIndex = this.trChildren.findIndex((item, index) => child === item);
      if (childDomIndex < 0) {
        childDomIndex = this.data.findIndex((v) => v[this.rowKey] === keyValue) + 1;
      }
      const dataLen = this.trChildren.filter((v) => !v.disabled && v.keyValue).length;
      if (childDomIndex === 0) {
        check ? this.selectionAll() : this.clearSelection();
        return;
      }

      if (check) {
        if (keyValue) {
          this.backData.push(child);
        }
        this.backIndexData.push(childDomIndex - 1);
      } else {
        const index = this.backData.findIndex((v) => v[this.rowKey] === keyValue);
        const idx = this.backIndexData.findIndex((item) => item === childDomIndex - 1);
        if (keyValue) {
          this.backData.splice(index, 1);
        }
        this.backIndexData.splice(idx, 1);
      }

      const domCheckAll = this.trChildren.find((item, index) => index > 0 && !item.checked && !item.disabled);
      if (!domCheckAll) {
        theadChildren.indeterminate = false;
        theadChildren.checked = true;
      } else {
        theadChildren.indeterminate = true;
        theadChildren.checked = false;
      }

      if (this.backIndexData.length === 0) {
        theadChildren.indeterminate = false;
      }

      if (!emit) {
        this.$emit("selection-change", {
          detail: {
            value: this.backData,
            index: this.backIndexData,
          },
        });
      }
    },
  },
};
</script>

<style lang="scss">
$border-color: #ebeef5;

.uni-table-scroll {
  width: 100%;
  /* #ifndef APP-NVUE */
  overflow-x: auto;
  /* #endif */
}

.uni-table {
  position: relative;
  width: 100%;
  border-radius: 5px;
  // box-shadow: 0px 0px 3px 1px rgba(0, 0, 0, 0.1);
  background-color: #fff;
  /* #ifndef APP-NVUE */
  box-sizing: border-box;
  display: table;
  overflow-x: auto;
  ::v-deep .uni-table-tr:nth-child(n + 2) {
    &:hover {
      background-color: #f5f7fa;
    }
  }
  ::v-deep .uni-table-thead {
    .uni-table-tr {
      // background-color: #f5f7fa;
      &:hover {
        background-color: #fafafa;
      }
    }
  }
  /* #endif */
}

.table--border {
  border: 1px $border-color solid;
  border-right: none;
}

.border-none {
  /* #ifndef APP-NVUE */
  border-bottom: none;
  /* #endif */
}

.table--stripe {
  /* #ifndef APP-NVUE */
  ::v-deep .uni-table-tr:nth-child(2n + 3) {
    background-color: #fafafa;
  }
  /* #endif */
}

/* 表格加载、无数据样式 */
.uni-table-loading {
  position: relative;
  /* #ifndef APP-NVUE */
  display: table-row;
  /* #endif */
  height: 50px;
  line-height: 50px;
  overflow: hidden;
  box-sizing: border-box;
}
.empty-border {
  border-right: 1px $border-color solid;
}
.uni-table-text {
  position: absolute;
  right: 0;
  left: 0;
  text-align: center;
  font-size: 14px;
  color: #999;
}

.uni-table-mask {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  background-color: rgba(255, 255, 255, 0.8);
  z-index: 99;
  /* #ifndef APP-NVUE */
  display: flex;
  margin: auto;
  transition: all 0.5s;
  /* #endif */
  justify-content: center;
  align-items: center;
}

.uni-table--loader {
  width: 30px;
  height: 30px;
  border: 2px solid #aaa;
  // border-bottom-color: transparent;
  border-radius: 50%;
  /* #ifndef APP-NVUE */
  animation: 2s uni-table--loader linear infinite;
  /* #endif */
  position: relative;
}

@keyframes uni-table--loader {
  0% {
    transform: rotate(360deg);
  }

  10% {
    border-left-color: transparent;
  }

  20% {
    border-bottom-color: transparent;
  }

  30% {
    border-right-color: transparent;
  }

  40% {
    border-top-color: transparent;
  }

  50% {
    transform: rotate(0deg);
  }

  60% {
    border-top-color: transparent;
  }

  70% {
    border-left-color: transparent;
  }

  80% {
    border-bottom-color: transparent;
  }

  90% {
    border-right-color: transparent;
  }

  100% {
    transform: rotate(-360deg);
  }
}
</style>
